/**
 * Copyright (c) 2018-2024, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: trace event test 
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2025-05-17     JasonHu           Init
 */

#include <test/integration.h>
#define NX_LOG_NAME "trace"
#include <base/trace.h>
#include <base/log.h>
#include <base/debug.h>
#include <base/string.h>

#ifdef CONFIG_NX_TEST_INTEGRATION_TRACE

NX_PRIVATE void HandleRecord(NX_EventRecord *record)
{
    static int i = 0;

    NX_LOG_D("[%d] header: id=%x, ver=%x, task:%d, kw:%d, time:%d", 
        i++, record->header.id, record->header.version, record->header.task, record->header.keyword, record->header.time);
    NX_LOG_D("data: %s", record->data);

}

#define TEST_EVENT_NAME "TestEvent"
#define TEST_SOURCE_NAME "TestSource0"

NX_PRIVATE NX_U32 EventReader(void *arg)
{
    NX_Tracer *trace;
    NX_EventRecord record;
    NX_Size count = 0;
    NX_LOG_D("start event reader");

    trace = NX_TraceAttach(TEST_EVENT_NAME);
    while (1)
    {
        // read from log
        if (NX_TraceLog(trace, &record, 1, &count) == NX_EOK)
        {
            HandleRecord(&record);
        }
    }
    NX_TraceDeattach(trace);
}

NX_PRIVATE NX_U32 EventWriter(void *arg)
{
    NX_EventSource *source = (NX_EventSource *)arg;
    
    char buf[32];

    NX_EVENT_HEADER_DEFINE(hdr);
    hdr.level = 1;
    hdr.task = NX_ThreadSelf()->tid;
    hdr.version = 1;

    static int i = 0;

    int tests = 100;

    NX_LOG_D("start event writer");
    while (--tests > 0)
    {
        hdr.id = i++;

        int j;
        for (j = 0; j < 10; j++)
        {
            NX_MemSet(buf, 0, 32);
            NX_SNPrintf(buf, 32, "event data:%d-%d", j, i);
            if (NX_TraceEventWrite(source, &hdr, buf, NX_StrLen(buf)) != NX_EOK)
            {
                NX_LOG_W("write event failed!");
            }
        }
        NX_ThreadSleep(100);
    }

    NX_LOG_D("write event test done!");
}

NX_PRIVATE void TraceEventTest(void)
{
    NX_PRIVATE NX_Thread *TraceEventWriterThread;
    NX_PRIVATE NX_Thread *TraceEventReaderThread;

    NX_EventSource *source = NX_EventSourceCreate(TEST_SOURCE_NAME);
    NX_EventSourceRegister(source, TEST_EVENT_NAME);

    NX_EventSourceEanble(source, NX_True);

    NX_ThreadStart(TraceEventWriterThread = NX_ThreadCreate("TraceEventWriter", EventWriter, source, NX_THREAD_PRIORITY_NORMAL));
    NX_ThreadStart(TraceEventReaderThread = NX_ThreadCreate("TraceEventReader", EventReader, NX_NULL, NX_THREAD_PRIORITY_NORMAL));

    /* wait trace task done */
    NX_ThreadWait(TraceEventWriterThread, NX_NULL);
    NX_LOG_D("term trace event reader");

    NX_ThreadTerminate(TraceEventReaderThread, 0);
    NX_ThreadWait(TraceEventReaderThread, NX_NULL);

    NX_LOG_D("unregister test event source");

    NX_EventSourceEanble(source, NX_False);
    NX_EventSourceUnregister(source);
}

NX_INTEGRATION_TEST(NX_TraceEvent)
{
    // create trace event
    NX_TraceEvent *event = NX_TraceEventCreate(TEST_EVENT_NAME, 256);
    NX_TraceEventEnable(event);

    TraceEventTest();

    NX_TraceEventDisable(event);
    NX_TraceEventDestroy(event);
    NX_LOG_D("destroy trace event");

    return NX_EOK;
}

#endif
